Wir beschäftigen uns mit den Daten des Bundesamts für Meteorologie. Wir haben dafür einen Export der Wetterstation Jungfraujoch (3571 m ü.M.) vom Jahr 2020. Diese Daten haben wir vom IDAWEB des Bundesamts für Meteorologie erhalten. Der Bestellschein ist im Anhang enthalten.
In diesem Notebook nutzen wir Plotly, um interaktive Time Series Plots zu generieren. Plotly ist eine benutzerfreundliche Datenvisualisierungssoftware, die hochentwickelte Visualisierungswerkzeuge bietet. Das Hinzufügen von Interaktion zu Visualisierungen eröffnet eine grosse Vielfalt an Möglichkeiten. Wir können verschiedene Visualisierungen derselben Daten auf Abruf präsentieren, zoomen, schwenken, filtern und scrollen implementieren. Anbei findet man die Dokumentation von Plotly unter folgenden Link: https://plotly.com/r/.
Während Plotly und ggplot2 beide Visualisierungen generieren, haben beide Vor- und Nachteile. Die Library ggplot2 kann mit einer sehr simplen Syntax verwendet werden, es lassen sich aber sehr einfach und modular Komplexitäten einbauen. Die Library bietet eine grosse Bandbreite an visuellen Möglichkeiten. Allerdings verwendet ggplot2 eine unterschiedliche Syntax als restliches R. Aus unserer Sicht ist der grösste Nachteil, dass keine interaktiven Plots möglich sind.
Genau dieses Manko füllt Plotly, welches automatisch interaktive Grafiken erstellt. Sobald also dem Anwender Möglichkeiten wie die Auswahl von Daten, Zoom oder Selektion von Punkten ermöglicht werden sollen, ist Plotly die Alternative. Die kleinere Anzahl von Farbpaletten ist in diesem Fall nur ein kleiner Wehrmutstropfen.
library(plotly)
library(corrplot)
library(lubridate)
library(tidyverse)
library(PerformanceAnalytics)
data_unclean <- read.csv(file = "Meteodaten.csv", sep = ";")
data_unclean <- data.frame(lapply(data_unclean, as.numeric))
data_unclean$time <- ymd_hm(data_unclean$time)
data <- data_unclean
data <- data %>%
select(time,
"boeenspitze" = fkl010z1, # in Meter/Sekunde
"windgeschwindigkeit" = fkl010za, # in Meter/Sekunde
"sonnenscheindauer" = sre000z0, # in Minuten
"gesamtbewoelkung" = nto000s0, # in octas
"luftfeuchtigkeit" = ure200s0, # in Prozent
"lufttemperatur" = tre200s0, # in Grad Celsius
"luftdruck" = prestas0 # in Hectopascal
) # Erweiterbar :)
corrData <- cor(data_unclean[3:31], use = "pairwise.complete.obs")
corrplot.mixed(corrData, lower = "ellipse", upper = "number", order = "alphabet", tl.pos = "lt", diag = "n", number.cex = 0.4)
Im ganzen Datensatz haben wir zu viele Variablen um eine verständliche Visualisierung über die Korrelationen aller Variablen zu erstellen. Jedoch lohnt sich diese Erstellung dieser Visualisierung um zu bestimmmen, welche Features man im reduzierten Datensatz übernehmen möchte. Das Bundesamt für Meteorologie hat die Namen dieser Variablen kodiert, deswegen müssen wir anhand der mitgelieferten Tabelle schauen, für was diese Codes stehen:
| Parameter | Einheit | Beschreibung |
|---|---|---|
| uto200s0 | g/m^2 | Absolute Luftfeuchtigkeit 2 m über Boden; Momentanwert |
| ns2000s0 | octas | Betrag der mittleren Wolken |
| ns1000s0 | octas | Betrag der untersten Wolken |
| fkl010z1 | m/s | Böenspitze (Sekundenböe); Maximum |
| xchills0 | °C | Chill Temperatur; Momentanwert |
| pva200s0 | hPa | Dampfdruck 2 m über Boden; Momentanwert |
| pvd200s0 | hPa | Dampfdruckdefizit 2 m über Boden; Momentanwert |
| tre2desd | °C | Differenz Lufttemperatur 2 m über Boden - Taupunkt; Momentanwert |
| tpp200s0 | °C | Feuchtpotentielle Temperatur 2 m über Boden; Momentanwert |
| tps200s0 | °C | Feuchttemperatur (Psychrometertemperatur) 2 m über Boden; Momentanwert |
| nto000s0 | octas | Gesamtbewölkung |
| gor000za | W/m^2 | Globalstrahlung; Standardabweichung |
| gre000z0 | W/m^2 | Globalstrahlung; Zehnminutenmittel |
| oli000z0 | W/m^2 | Langwellige Einstrahlung; Zehnminutenmittel |
| prestas0 | hPa | Luftdruck auf Barometerhöhe (QFE); Momentanwert |
| pp0qnhs0 | hPa | Luftdruck reduziert auf Meeresniveau mit Standardatmosphäre (QNH); Momentanwert |
| tre200s0 | °C | Lufttemperatur 2 m über Boden; Momentanwert |
| pvamixs0 | g/kg | Mischungsverhältnis |
| uor200s0 | % | Original Luftfeuchtigkeit 2 m über Boden; Momentanwert |
| tpo200s0 | °C | Potentielle Temperatur 2 m über Boden; Momentanwert |
| ure200s0 | % | Relative Luftfeuchtigkeit 2 m über Boden; Momentanwert |
| sre000z0 | min | Sonnenscheindauer; Zehnminutensumme |
| usp200s0 | g/kg | Spezifische Luftfeuchtigkeit 2 m über Boden; Momentanwert |
| pvaices0 | hPa | Sättigungsdampfdruck über Eis; Momentanwert |
Leider sind die meisten hohen Korrelationen keine richtige Korrelationen, sondern zwei Variablen, welche etwas ähnliches beschreiben oder physikalische Zusammenhänge sind. Beispiel dafür ist die Korrelation von sre000z0 (Sonnenscheindauer) und gre000z0 (Globalstrahlung).
Wir entscheiden uns grundsätzlich für diese Werte:
| Spalte | Kurzbeschrieb | Definition |
|---|---|---|
| fkl010za | Windgeschwindigkeit | Die Windgeschwindigkeit ist die Geschwindigkeit der Luft gegenüber dem Boden. |
| sre000z0 | Sonnenscheindauer | Als Sonnenschein wird zweierlei bezeichnet: der Lichtschein der Sonne (also die Wirkung der Sonnenstrahlen auf die Erde), und eine Wetterlage mit geringer oder keiner Bewölkung. |
| nto000s0 | Gesamtbewölkung | Eine Schätzung, wie viele Achtel des Himmels mit Wolken bedeckt ist. |
| ure200s0 | Luftfeuchtigkeit | Die Luftfeuchtigkeit oder Luftfeuchte ist der Anteil des Wasserdampfs am Gasgemisch der Luft. |
| tre200s0 | Lufttemperatur | Als Lufttemperatur wird jene Temperatur der bodennahen Atmosphäre bezeichnet, die weder von Sonnenstrahlung noch von Bodenwärme oder Wärmeleitung beeinflusst ist. |
| prestas0 | Luftdruck | Der Luftdruck an einem beliebigen Ort der Erdatmosphäre ist der hydrostatische Druck der Luft, der an diesem Ort herrscht. |
Aus folgenden Gründen:
| Kurzbeschrieb | Begründung |
|---|---|
| Windgeschwindigkeit | Die Windgeschwindigkeit ist eine der meist beachteten Wetterkennzahlen. Wir verwenden sie zur Überprüfung der Korrelationen |
| Sonnenscheindauer | Dieses Feature wird benötigt, um die vierte Hypothese bestätigen oder verwerfen zu können. |
| Gesamtbewölkung | Dieses Feature wird benötigt, um die vierte Hypothese bestätigen oder verwerfen zu können. |
| Luftfeuchtigkeit | Diese Werte verwenden wir, um mögliche Korrelationen festzustellen. |
| Lufttemperatur | Dieses Feature wird benötigt, um die zweite und dritte Hypothese bestätigen oder verwerfen zu können. |
| Luftdruck | Die Werte verwenden wir, um den physikalischen Zusammenhang zwischen Druck und Temperatur zu bestätigen. |
corrData <- data %>%
select(
"boeenspitze",
"windgeschwindigkeit",
"sonnenscheindauer",
"luftfeuchtigkeit",
"lufttemperatur",
"luftdruck",
) %>%
cor(., use = "pairwise.complete.obs")
corrplot.mixed(corrData, lower = "ellipse", upper = "number", order = "alphabet", tl.pos = "lt", diag = "u")
Die einzigen ausgeprägten Korrelationen (+/- 0.7) sind Luftdruck ~ Lufttemperatur und Böenspitzen ~ Windgeschwindigkeit. Leider ist die erste Korrelation ein physikalischer Zusammenhang. Die zweite Korrelation ist auch nicht überraschend, da der Wert der Böenspitzen abhängig von der Geschwindkeit des Windes ist. Die stärkste negative Korrelation hat einen Wert von nur -0.39.
Die Hypothese verwerfen wir, da wir im kleinen Korrelationsplot nur zwei Werte über 0.7 haben. Diese sind erst noch nicht aussagekräftig, wie wir gerade beschrieben haben.
Hier nehmen wir 0°C als Referenz, da der Gefrierpunkt von Wasser (unter idealen Bedingungen) bei 0°C liegt. Das Jungfraujoch ist auch das obere Ende des grössten Gletschers der Schweiz. Entsprechend wäre es für diesen Gletscher schlecht, zu hohe Temperaturen erleiden zu müssen.
granularity <- "day"
plot <- data %>%
group_by(time = floor_date(time, granularity)) %>%
summarise(
mean_lufttemperatur = mean(lufttemperatur, na.rm = T),
mean_luftfeuchtigkeit = mean(luftfeuchtigkeit, na.rm = T),
mean_windgeschwindigkeit = mean(windgeschwindigkeit, na.rm = T),
mean_luftdruck = mean(luftdruck, na.rm = T),
sonnenscheindauer_h = sum(sonnenscheindauer, na.rm = T) / 60
)
plot$windchill <- (13.12 + 0.6215 * plot$mean_lufttemperatur) + (0.3965 * plot$mean_lufttemperatur - 11.37) * (plot$mean_windgeschwindigkeit * 3.6)^0.16
plot_ly(
data = plot,
type = "scatter",
mode = "lines",
width = 900,
height = 700
) %>%
layout(
showlegend = TRUE,
title = "Wetterverlauf im Jungfraujoch über das Jahr 2020",
xaxis = list(
title = "Zeitachse",
rangeslider = list(visible = T),
rangeselector = list(
buttons = list(
list(count = 1, label = "1m", step = "month", stepmode = "backward"),
list(step = "all")
)
),
zerolinecolor = "#C5C5C5",
zerolinewidth = 2,
gridcolor = "#C5C5C5",
type = "date"
),
yaxis = list(
title = "",
zerolinecolor = "#C5C5C5",
zerolinewidth = 2,
gridcolor = "#C5C5C5"
),
plot_bgcolor = "#ffff",
margin = 0.2,
shapes = list(
list(
type = "area",
fillcolor = "lightblue",
line = list(color = "lightblue"),
opacity = 0.2,
x0 = "2020-01-01",
x1 = "2020-03-21",
yref = "paper",
y0 = 0,
y1 = 1
),
list(
type = "area",
fillcolor = "green",
line = list(color = "green"),
opacity = 0.1,
x0 = "2020-03-21",
x1 = "2020-06-21",
yref = "paper",
y0 = 0,
y1 = 1
),
list(
type = "area",
fillcolor = "yellow",
line = list(color = "yellow"),
opacity = 0.15,
x0 = "2020-06-21",
x1 = "2020-09-23",
yref = "paper",
y0 = 0,
y1 = 1
),
list(
type = "area",
fillcolor = "chocolate",
line = list(color = "chocolate"),
opacity = 0.1,
x0 = "2020-09-23",
x1 = "2020-12-21",
yref = "paper",
y0 = 0,
y1 = 1
),
list(
type = "area",
fillcolor = "lightblue",
line = list(color = "lightblue"),
opacity = 0.2,
x0 = "2020-12-21",
x1 = "2020-12-31",
yref = "paper",
y0 = 0,
y1 = 1
)
)
) %>%
add_trace(x = ~time, y = ~mean_lufttemperatur, name = "Lufttemperatur °C", line = list(color = "black")) %>%
add_trace(x = ~time, y = ~windchill, name = "Gefühlte Temperatur (Windchill) °C", line = list(color = "red"), opacity = 0.2)
Dieser Plot wurde anhand von Hintergrundsfarben in Jahreszeiten unterteilt.
| Farbe | Jahreszeit |
|---|---|
| Blau | Winter |
| Grün | Frühling |
| Gelb | Sommer |
| Braun | Herbst |
Aufgrund der visuellen Zeitreihenanalyse verwerfen wir die Hypothese, da in diesem Jahr die mittlere Tagestemperatur im Sommer regelmässig über 0°C steigt.
plot <- data %>%
group_by(time = format(time, "%H:%M")) %>%
summarise(
mean_lufttemperatur = mean(lufttemperatur, na.rm = T),
mean_luftfeuchtigkeit = mean(luftfeuchtigkeit, na.rm = T),
mean_windgeschwindigkeit = mean(windgeschwindigkeit, na.rm = T),
mean_luftdruck = mean(luftdruck, na.rm = T),
sonnenscheindauer_h = mean(sonnenscheindauer, na.rm = T)
)
plot_ly(
data = plot,
type = "scatter",
mode = "lines",
width = 900,
height = 700
) %>%
add_trace(x = ~time, y = ~mean_lufttemperatur, name = "Lufttemperatur °C") %>%
add_trace(x = ~time, y = ~mean_luftfeuchtigkeit, name = "Luftfeuchtigkeit in %", visible = "legendonly") %>%
add_trace(x = ~time, y = ~sonnenscheindauer_h, name = "Sonnenscheindauer in h", visible = "legendonly") %>%
add_trace(x = ~time, y = ~mean_windgeschwindigkeit, name = "Windgeschwindigkeit in m/s", visible = "legendonly") %>%
add_trace(x = ~time, y = ~mean_luftdruck, name = "Luftdruck in hPa", visible = "legendonly") %>%
layout(
showlegend = TRUE,
title = "Durchschnittliche Temperatur über den Tag auf dem Jungfraujoch im Jahr 2020",
xaxis = list(
title = "Uhrzeit",
rangeslider = list(visible = T),
rangeselector = list(
buttons = list(
list(count = 1, label = "1m", step = "month", stepmode = "backward"),
list(step = "all")
)
),
zerolinecolor = "#C5C5C5",
zerolinewidth = 2,
gridcolor = "#C5C5C5"
),
yaxis = list(
title = "",
zerolinecolor = "#C5C5C5",
zerolinewidth = 2,
gridcolor = "#C5C5C5"
),
plot_bgcolor = "#ffffff",
margin = 0.2,
shapes = list(
type = "rect",
fillcolor = "yellow",
line = list(color = "yellow"),
opacity = 0.2,
x0 = 33.4,
x1 = 49.1,
y0 = -6.1,
y1 = -4.4
)
)
Markierung beim Plot:
| Farbe | Bedeutung |
|---|---|
| Gelb | Zeitintervall zwischen frühesten und spätesten Sonnenaufgang 2020 |
Die mittlere Temperatur befindet sich tatsächlich zwischen vier und fünf Uhr am tiefsten Punkt. Da der berechnete früheste Sonnenenaufgang im Jahr 2020 kurz nach 05:30 (auf dem Berg oben vermutlich noch früher) war, bestätigen wir unsere Hypothese.
Zur Beantwortung der Hypothese berechnen wir die Anzahl Stunden, an welchen die Sonne gescheint hat. Dies machen wir mit der Granularität von einer Stunde.
visualize <- function(granularity) {
plot <- data %>%
group_by(time = floor_date(time, granularity)) %>%
summarise(
mean_lufttemperatur = mean(lufttemperatur, na.rm = T),
mean_luftfeuchtigkeit = mean(luftfeuchtigkeit, na.rm = T),
mean_windgeschwindigkeit = mean(windgeschwindigkeit, na.rm = T),
mean_luftdruck = mean(luftdruck, na.rm = T),
sonnenscheindauer_h = sum(sonnenscheindauer, na.rm = T) / 60
)
plot_ly(
data = plot,
type = "scatter",
mode = "lines",
width = 900,
height = 700
) %>%
add_trace(x = ~time, y = ~sonnenscheindauer_h, name = "Sonnenscheindauer in h") %>%
layout(
showlegend = FALSE,
title = "Sonnenscheindauer auf dem Jungraujoch im 2020 in Stunden",
xaxis = list(
title = "Zeitachse",
rangeslider = list(visible = T),
rangeselector = list(
buttons = list(
list(count = 1, label = "1m", step = "month", stepmode = "backward"),
list(step = "all")
)
),
zerolinecolor = "#ffff",
zerolinewidth = 2,
gridcolor = "ffff"
),
yaxis = list(
title = "",
zerolinecolor = "#ffff",
zerolinewidth = 2,
gridcolor = "ffff"
),
plot_bgcolor = "#e5ecf6",
margin = 0.2
)
}
visualize("hour")
Mit stündlichen Daten kann unsere Hypothese nicht beantwortet werden. Wir wechseln deshalb auf tägliche Werte.
visualize("day")
Anhand täglicher Werte können wir unsere Hypothese immernoch nicht beantworten, die Grafik ist noch viel zu unübersichtlich. Wir schalten deshalb auf wöchentliche Werte.
visualize("week")
Die Sonnenscheindauer variiert durch das ganze Jahr stark, deswegen verwerfen wir unsere Hypothese. Vermutlich waren das Schlechtwetterperioden mit viel Bewölkung über mehrere Tage oder Wochen. Für diese Hypothese würde sich ein Vergleich über mehrere Jahre gut anbieten.